import { constantRoutes, error404 } from '@/router'
import { menuMap } from '@/router/menu/index'
import { mts } from '../types'
import http from '@/utils/http'

import Layout from '@/layout'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some((role) => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach((route) => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

const state = () => ({
  routes: constantRoutes,
  menuRoutes: [],
  fetchMenuCount: 0,
  remoteRoutes: []
})

const mutations = {
  [mts.setRoutes]: (state, routes) => {
    state.remoteRoutes = routes
    state.routes = constantRoutes.concat(routes)
  },
  [mts.setMenuRoutes]: (state, routes) => {
    state.menuRoutes = routes
  },
  [mts.updateMenuCount]: (state, count) => {
    state.fetchMenuCount++
  },
  [mts.resetMenuCount]: (state, count) => {
    state.fetchMenuCount = 0
  }
}

// 解决打包报错 ：Critical dependency: the request of a dependency is an expression
export const loadView = (view) => {
  // 路由懒加载
  return () => Promise.resolve(require(`@/views/${view}`).default)
}
/**
 * @description 递归方式序列化返回值
 */
function recursionAddMeta(arr) {
  if (!Array.isArray(arr)) return

  for (let i = 0; i < arr.length; i++) {
    const node = arr[i]

    const baseNode = { ...menuMap[node.path] }
    node['meta'] = {
      title: node.label,
      icon: node.icon,
      type: node.type,
      sortOrder: node.sortOrder,
      id: node.id,
      parentId: node.parentId,
      noCache: node.keepAlive === '0'
    }

    Object.assign(node['meta'], baseNode.meta)
    delete baseNode.meta
    Object.assign(node, baseNode)

    // children
    if (Array.isArray(node.children)) {
      recursionAddMeta(node.children)
    }
  }
}

const actions = {
  cleanRemoteRoute({ commit }, data) {
    commit(mts.setRoutes, [])
  },
  resetFetchCount({ commit }, data) {
    commit(mts.resetMenuCount)
  },
  /**
   * 根据用户角色生成路由配置
   *
   * @param {Object} commit - Vuex 的 commit 方法，用于提交状态变更
   * @param {Array} roles - 用户的角色列表
   * @returns {Promise} - 解析为包含生成的路由配置的对象的 Promise
   *
   * @throws {Error} - 如果获取菜单数据失败，则抛出错误
   */
  generateRoutes({ commit }, roles) {
    const permissions = []

    /**
 * 过滤并处理异步路由映射表
 *
 * @param {Array} asyncRouterMap - 异步路由映射表的数组
 * @returns {Array} - 过滤和处理后的路由映射表数组
 *
 * @function filterAsyncRouter
 * @description 这个函数通过过滤和处理路由映射表，确保只有符合条件的路由被保留，并设置了必要的重定向和权限检查。
 */
    function filterAsyncRouter(asyncRouterMap) {
      return asyncRouterMap.filter((route) => {
        if (route.component) {
          route.component = loadView(route.component)
        }
        // 提取按钮权限，并返回false删除该按钮路由
        if (route.menuType === 1) {
          if (!permissions.includes(route.permission)) {
            permissions.push(route.permission)
          }
          return false
        }
        if (route.children && route.children.length) {
          route.children = filterAsyncRouter(route.children)
          // 这意味着用户访问这个路由时，他们将被自动重定向到它的第一个子路由。
          route.redirect = route.children[0].path
        } else {
          Reflect.deleteProperty(route, 'children')
          Reflect.deleteProperty(route, 'redirect')
        }
        return true
      })
    }

    function findFirstPath(route) {
      console.log('findFirstPath', route)
      if (!route.children || route.children.length === 0) {
        return route.path
      }
      // 解决路由跳转问题
      // 默认跳转当前路由地址，不去跳转子路由
      if (route.permission === 'CURRENT_URL') {
        return route.path
      }
      for (let i = 0; i < route.children.length; i++) {
        const result = findFirstPath(route.children[i])
        if (result) {
          return result
        }
      }
      return ''
    }
    return new Promise((resolve, reject) => {
      http
        .getMenu({ parentId: '-1' })
        .then((response) => {
          let { data } = response
          const { code } = response
          data = formateMenu(data)
          if (code === '200') {
            if (!data) {
              commit(mts.setRoutes, [])
              reject({
                routes: [],
                path: '/401'
              })
            } else {
              const sdata = JSON.parse(JSON.stringify(data))
              const rdata = JSON.parse(JSON.stringify(data))
              const sidebarRoutes = filterAsyncRouter(sdata)
              const rewriteRoutes = filterAsyncRouter(rdata)
              const firstPath = findFirstPath(rewriteRoutes[0])

              commit(mts.setMenuRoutes, data)

              // 增加一级路由用于支持一级菜单/二级菜单/多级菜单展示
              const dynamicalRoute = [
                {
                  path: '/',
                  component: Layout,
                  name: 'home',
                  children: sidebarRoutes,
                  redirect: firstPath
                }
              ]
              dynamicalRoute.push(error404)
              commit(mts.setRoutes, dynamicalRoute)
              resolve({ routes: dynamicalRoute })
              commit(mts.updateMenuCount)
            }
          } else {
            commit(mts.setRoutes, [])
            reject({ routes: [] })
          }
        })
        .catch(() => {
          commit(mts.resetMenuCount)
        })
    })
  }
}

// 重组菜单数据格式，满足路由格式

export const formateMenu = (data) => {
  return data.map((item) => {
    // 处理路由路径 , 兼容hash路由
    // 比如组件路径配置的是全路径，从[#]后截取，作为组件的路径
    const regexHttp = /^(http|https):\/\//
    const hashRegex = /#(\/[^?]+)/
    const path = regexHttp.test(item.resourceUrl)
      ? item.resourceUrl.match(hashRegex)[1]
      : item.resourceUrl

    return {
      path,
      visible: item.hidden === 1,
      component: item.modulePath,
      menuType: item.type,
      ...item,
      children: item.children ? formateMenu(item.children) : []
    }
  })
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
